
import {buildGFSWind} from "./gfs-wind.js";
import {scalarProduct} from "../scalarProduct.js";
import {length} from "../../util/math.js";

export function buildGFSWindPowerDensity(windFile, airdensFile) {

    const windGrid = buildGFSWind(windFile);
    const windField = windGrid.field();
    const windValueAt = windField.valueAt;
    const windNearest = windField.nearest;
    const windBilinear = windField.bilinear;

    const airdensGrid = scalarProduct(airdensFile, /air_density/, {hasMissing: false, legacyName: "air_density"});
    const airdensField = airdensGrid.field();
    const airdensValueAt = airdensField.valueAt;
    const airdensIsDefined = airdensField.isDefined;
    const airdensNearest = airdensField.nearest;
    const airdensBilinear = airdensField.bilinear;

    function wpd(wind, ρ) {
        const velocity = length(wind);
        return 0.5 * ρ * velocity ** 3;
    }

    // CONSIDER: We cannot pre-compute the wind power density function and then rely on bilinear interpolation in the
    //           shader because the wpd function has a cubic term. Instead, the shader should support a blending of
    //           two bilinear lookups with a custom function. This requires making the existing shader source more
    //           generic, so it can support multiple textures.
    //
    // const data = new Float32Array(airdensGrid.field().size);
    // for (let i = 0; i < data.length; i++) {
    //     data[i] = wpd(windValueAt(i), airdensValueAt(i));
    // }

    const field = {
        valueAt: i => wpd(windValueAt(i), airdensValueAt(i)),
        scalarize: x => x,
        isDefined: airdensIsDefined,
        nearest: (λ, φ) => wpd(windNearest(λ, φ), airdensNearest(λ, φ)),
        bilinear: (λ, φ) => wpd(windBilinear(λ, φ), airdensBilinear(λ, φ)),
    };

    return {
        validTime: airdensGrid.validTime,
        grid: airdensGrid.grid,
        field: () => field,
        valueInRange(t) { return this.scale.valueInRange(t); },
    };
}
